#pragma once
#include<iostream>
#include<vector>
#include"Sem.hpp"
#include"Mutex.hpp"


namespace RingBufferModule
{
    using namespace SemModule;
    using namespace LockModule;

    template<typename T>
    class RingBuffer
    {
    public:
        RingBuffer(int cap)
            :_ring(cap)
            ,_cap(cap)
            ,_c_pos(0)
            ,_p_pos(0)
            ,_datasem(0)
            ,_spacesem(cap)
        {}

        void Enqueue(const T& in)
        {
            _spacesem.P();//申请空间
            
            {
                LockGuard lockguard(_p_mutex);
                _ring[_p_pos]=in;
                _p_pos++;
                _p_pos%=_cap;
            }

            _datasem.V();

        }

        void Pop(T* out)
        {
            _datasem.P();

            {
                LockGuard lockguard(_c_mutex);
                *out =_ring[_c_pos];
                _c_pos++;
                _c_pos%=_cap;
            }

            _spacesem.V();
        }
        ~RingBuffer()
        {}
    private:
        std::vector<T> _ring;
        int _cap;              //总容量
        int _c_pos;            //消费者位置
        int _p_pos;            //生产者位置

        Sem _datasem;          //数据信号量
        Sem _spacesem;         //空间信号量

        Mutex _c_mutex;        //消费者之间的锁
        Mutex _p_mutex;        //生产者之间的锁
    };

}